#include "shader.h"
#include <exception>
#include <string>
#include <fstream>
#include <sstream>
#include "boost/filesystem.hpp"

namespace moogle
{
  shader::shader(const std::string& src_code, SHADER_TYPE type)
  {
    // Create shader
    _gl_obj = glCreateShader(static_cast<GLenum>(type));

    // Assign source code
    const GLchar* str_array = src_code.c_str();
    glShaderSource(gl_obj(), 1, &str_array, NULL);

    // Compile
    glCompileShader(gl_obj());

    // Check for errors
    GLint compile_status;
    glGetShaderiv(gl_obj(), GL_COMPILE_STATUS, &compile_status);
    if (compile_status == GL_FALSE)
		{
      glDeleteShader(gl_obj());
      throw std::runtime_error("Shader compilation failed");
		}
  }

  shader shader::from_file(const std::string& src_path)
  {
    std::string ext = boost::filesystem::extension(src_path);

    if (ext == "fp")
      return shader::from_file(src_path, VERTEX_SHADER);

    return shader::from_file(src_path, FRAGMENT_SHADER);
  }

  shader shader::from_file(const std::string& src_path, SHADER_TYPE type)
  {
    std::ifstream src_file(src_path);

    std::stringstream buffer;
    buffer << src_file.rdbuf();

    return shader(buffer.str(), type);
  }

  GLuint shader::gl_obj()
  { return _gl_obj; }

  void shader_program::_init()
  {
    _gl_obj = glCreateProgram();
  }

  void shader_program::_attach_shader(shader* s)
  {
    glAttachShader(gl_obj(), s->gl_obj());
  }

  void shader_program::_link()
  {
    glLinkProgram(gl_obj());

    GLint link_status;
    glGetProgramiv(gl_obj(), GL_LINK_STATUS, &link_status);
    if (link_status == GL_FALSE)
		{
      glDeleteProgram(gl_obj());
      throw std::runtime_error("Shader link failed");
		}
  }

  GLuint shader_program::gl_obj()
  { return _gl_obj; }
}
